/*
 * Erlang node in java.
 * 
 * Send messages to {java, java@$(hostname)}
 * 
 * Listens for messages of types
 * 
 * {node,{name,hash},[nodes]}
 * {element,{Hash, Key, Value},[nodes]}
 * 	
 * (The third element, [nodes], is not implemented yet)
 * 
 */

package core1;
import com.ericsson.otp.erlang.*;
import java.io.IOException;
import java.util.ArrayList;

public class JavaNode {
	
	private String nodeName = "java";
	private String mboxName = "java";
	
	private OtpMbox mbox;
	
    // start the node up
    public boolean start() {
        try{
            init();
        }catch(Exception e){
            System.out.println("JavaNode init failed: " + e);
            return false;
        }

	// this will block and the caller will block until the loop exits
	loop();
 
        return true;
    }
    
    private void init() throws IOException {
        System.out.println("Starting jinterface node init...");
        OtpNode self = new OtpNode(nodeName);
        self.setCookie("apa");
        mbox = self.createMbox(mboxName);
    }
    
    private void loop() {
        System.out.println("Starting jinterface node loop...");
        boolean running = true;
        while(running){
            try{
                OtpErlangObject o = mbox.receive();
                System.out.println("Received a message");
                
                //System.out.println( "CLASS: " + o.getClass().toString() );
                
                if( o instanceof OtpErlangTuple) {
                	
                	OtpErlangTuple tup = (OtpErlangTuple) o;
                	
                	handleMessage(tup);
                
                } else {
                	System.out.println( "1: Something was sent in the wrong format." );
                }
                
            }catch(Exception e){
            	System.out.println("Exception in loop: " + e);
            	System.out.println(e.getStackTrace());
//                 running= false;
            }
        }
    }
    
    private void handleMessage(OtpErlangTuple msg) throws Exception {
    	
    	if( msg.elementAt(0) instanceof OtpErlangAtom ) {
    		
    		OtpErlangAtom identifier = (OtpErlangAtom) msg.elementAt(0);
    		
    		//System.out.println( "identifier.atomValue(): " + identifier.atomValue() );
    		
    		//A node has been added in the database
    		
    		if(identifier.atomValue().equals( "node") ) {
    			
    			System.out.println( "Node received!" );
    			
    			//Get information about the node
    			OtpErlangTuple nodeInfo = (OtpErlangTuple) msg.elementAt(1);
    			
    			//Get information from the tuple
    			OtpErlangLong hashKey  = (OtpErlangLong) nodeInfo.elementAt(0);
    			OtpErlangAtom nodeName = (OtpErlangAtom) nodeInfo.elementAt(1);
    			
			Globals.getInstance().mainRef.addUpdateMirrorNode(hashKey.longValue(), nodeName.toString());
			
		} else if (identifier.atomValue().equals("chord")) {
			
			System.out.println( "Chord node received!" );
    			
			//Get information about the node
			OtpErlangTuple nodeInfo = (OtpErlangTuple) msg.elementAt(1);
    			
			//Get information from the tuple
			OtpErlangLong hashKey  = (OtpErlangLong) nodeInfo.elementAt(0);
			OtpErlangAtom nodeName = (OtpErlangAtom) nodeInfo.elementAt(1);
    			
			OtpErlangLong predKey = (OtpErlangLong) nodeInfo.elementAt(2);
			
			ArrayList<Long> fingerKeys = null;
			
			if (nodeInfo.elementAt(3) instanceof OtpErlangList) {
				OtpErlangList fingerTable = (OtpErlangList) nodeInfo.elementAt(3);
				
				fingerKeys = new ArrayList<Long>();
				for(OtpErlangObject fingerKey:fingerTable.elements()) {
					fingerKeys.add(((OtpErlangLong) fingerKey).longValue());
				}
			}
    			
			Globals.getInstance().mainRef.addUpdateMirrorNode(hashKey.longValue(), nodeName.toString(),
                                            predKey.longValue(), fingerKeys);
    		
    		//An element has been added in the database
    		} else if (identifier.atomValue().equals( "element") ) {
    			
    			System.out.println( "Element received!" );

    			//Get information about the element
    			OtpErlangTuple elementInfo = (OtpErlangTuple) msg.elementAt(1);
    			
    			//Get information from the element
    			OtpErlangLong hashedKey = (OtpErlangLong) elementInfo.elementAt(0);
    			OtpErlangLong nodeKey = (OtpErlangLong) elementInfo.elementAt(1);
    			OtpErlangObject key = elementInfo.elementAt(2);
    			OtpErlangObject value = elementInfo.elementAt(3);
    			
    			Globals.getInstance().mainRef.addMirrorElement(hashedKey.longValue(), nodeKey.longValue(),
                                          key.toString(), value.toString());
    		
    		} else {
    			
    			System.out.println( "Invalid identifier received" );
    		}
    	
    	} else {
    		
    		System.out.println( "2: Something was sent in the wrong format." );
    	}
    }
}
